查看原文
其他

爱奇艺自研UI引擎渲染技术分析

The following article is from 爱奇艺技术产品团队 Author Lyra team

点击上方开发者技术前线”,选择“星标”

13点21分打卡 就是真爱


来源:爱奇艺技术产品团队 | 本期责编:可可   

摘要


我们都知道,好的视频内容可以吸引更多用户。那么在好的内容基础上,我们希望用更好的架构及渲染技术,不断迭代出更轻、更炫、更平滑的客户端,保证用户有更好的体验。在此驱动下我们致力于开发一套高效的跨平台渲染引擎Lyra,为用户提供新的体验。本文主要详细阐述在PC客户端上引入的新渲染技术。



背景



爱奇艺PC客户端之前使用的UI引擎是公司内部开发的QuiLib。QuiLib是基于开源的uilib和DuiLib开发的轻量级的UI引擎。QuiLib使用了DirectUI框架,其主要思想就是控件无窗口化。虽然在很长一段时间内,QuiLib都发挥着至关重要的作用,但是随着渲染技术和计算机技术的发展,QuiLib暴露了它的很多缺点。


QuiLib的渲染的流程

QuiLib的动画Timer、业务逻辑、布局、渲染等均在主线程,这样每一个阶段的耗时都会导致整个流程的推迟或卡顿,其主要问题有:

(1)绘制性能差,如当UI元素进行alpha或者旋转变化时,paint慢且需要多次内存拷贝,效率很低;

(2)冗余layout,排版效率低,一次业务处理过程中若对某个节点多次操作,会导致该节点冗余layout;

(3)动画不流畅,每组动画都有独立的时间线,同时主线程负载太重,任何一环耗时,都会导致动画不平滑,用户体验差。

其次,在组件架构层面,QuiLib也存在一些欠缺。


组件架构图

 从组件架构图可以看出:QuiLib基于Windows和GDI图形库;QuiLib 没有利用D3D等3D图形技术来给UI渲染提速,并且重度使用了GDI,无法做到渲染跨平台化。这样会导致如下问题:不能充分利用显卡的性能,不支持跨平台化。



技术引入




为了解决现在的框架(即Quilib)具有的以上问题,我们做出了以下的技术解决方案:

(1)3D渲染:充分利用显卡性能,加速图形渲染速度; 

(2)异步渲染:把渲染流程细划为业务逻辑、样式变化、布局、生成渲染命令、执行渲染命令、合成渲染层和刷新到屏幕几个阶段;每个线程使用一个唯一的动画时间线,来驱动动画;

(3)分层渲染:根据情况,自动把某些频繁渲染的元素从主渲染层提升为单独的渲染层,这样每个层都进行单独的渲染流程,最后再把这些渲染结果合成并且上传到屏幕;

引入新的设计思想和渲染技术,能够让基于Lyra开发的PC应用运行更平滑,达到和mac系统上应用一样的平滑度。



技术实践




为了实践以上设计思想和渲染技术,我们开发了一个新的UI渲染引擎并且命名为Lyra(天琴座),寓意希望新的UI渲染引擎像天琴座一样灿烂。

跨平台和GPU渲染图形库

Lyra一开始就致力于跨平台和GPU加速渲染。通过调研和比较现在流行的图形库及游戏渲染引擎,Lyra最终选择了使用skia。


Lyra引擎组件架构图:阐述了新UI引擎的层级关系

 

skia具有如下这些优点:

(1)跨平台;

(2)高效基本图元渲染;

(3)高效的字体处理及文本渲染;

(4)丰富的图像格式支持;

(5)支持3D渲染,可以无缝切换为2D渲染。

得益于skia 3D & 2D backend的无缝切换,lyra可以针对不同的机器配置选择不同的渲染方式,优化Layered窗口这种需要渲染后处理的特殊情况,支持运行时渲染方式的自动fallback。也正是3D & 2D backend的无缝切换也导致skia资源占用很高,为了优化资源占用及命令序列化,也需要做很多侵占式的定制,在此不详述了。



异步渲染




Lyra使用了多线程渲染技术:UI主线程主要负责与用户交互,Render线程主要负责图形渲染。


Lyra新的渲染流程图


 如上图:Lyra把渲染流程细分为更多的步骤:Event&Message、样式变化、Layout、Paint(生成绘制命令)、Execute(执行绘制命令)、合成、刷新到窗口。在渲染过程中,比较耗时的几个点就是用户逻辑处理、Layout和执行渲染命令、合成。

Lyra把Paint以及其之前和Execute以及其之后分为两大块,这两大块是并行运行。这样的好处是:执行渲染命令的耗时不会导致用户响应延迟,主线程的Timer等比较耗时的逻辑也不会导致渲染延迟;同时形成渲染流水,执行灵活的帧选择策略,最大化渲染效率,提高响应速度。

动画系统由基于线程的唯一Timer来驱动,保证一个线程一个时间线,这样减少了Timer资源的消耗,提高了动画的渲染效率。同时将动画分为主线程动画和render线程动画,主线程动画操作逻辑渲染节点,Render线程动画驱动layer层相关动画。动画系统自动将不同的动画附着到不同的线程。通过如此设计可以支持3D动效、复杂动效,各部件联动,最大化动画帧率。



分层渲染




我们知道一个UI程序,大部分时候只有个别元素在响应事件。比如旋转时,理论上我们只需要绘制正在旋转的这个元素就可以。所以基于这种理念,Lyra实现了分层渲染技术,针对于每个元素,Lyra内部会根据情况创建新层或者销毁多余的层。

分层渲染,需要解决以下问题:各种树之间的逻辑关系;何时创建新的层。

我们用一个示例来说明分层技术的实现原理。



只有主层




在这个示例中,UI第一次展示时,只有主层,如下图所示:


创建分层渲染中的所有树:

(1)解析xml生成一棵Control树,这棵树主要负责处理事件和消息,以及管理各个Control的生命周期;

(2)生成一棵RenderObject树,这棵树的RenderObject和Control树中的Control有一一映射关系,并且RenderObject生命周期的管理完全由Control负责;

(3)Lyra根据需要会生成一棵RenderLayer树,同时也会生成一棵GraphicsLayer树;GraphicsLayer树上的结点和RenderLayer树上的结点有一一映射关系。



构建新层




当用户旋转其中一个元素时,就需要创建新的层。旋转C-5时,树之间的关系以及层之间关系就有如下图新的变化:

 

这里Lyra根据需要会生成新的层RL-Rotation(对应于RO-5)和RL-Fake(对应于RO-6)。



异步绘制




示例中的3层在UI主线程生成绘制命令,并且交换到Render线程,下图展示了异步绘制:


 

RenderLayer树来负责驱动关联于它上的RenderObject的Paint,生成绘制命令。 GraphicsLayer对应于真正的LyraSurface,会驱动RenderLayer生成绘制命令,并且把绘制命令交换到渲染线程。

 



合成




渲染线程在接收到绘制命令后,填充屏幕像素,如下图所示:



 Lyra合成器会驱动GraphicsLayer在渲染线程中执行绘制命令,并且合成绘制结果,最后刷新到屏幕上。




结语




本文主要简述了Lyra渲染技术相关的一些突破性工作:

(1)3D渲染、跨平台渲染;

(2)异步渲染,基于线程Timer驱动的动画系统;

(3)分层渲染。如果你想深入了解或者使用Lyra,可以直接在公众号上留言。

END

 

喜欢就点个好看吧!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存